/*
 * @Author: Wangjun
 * @Date: 2023-02-27 14:48:23
 * @LastEditTime: 2023-02-27 14:58:43
 * @LastEditors: Wangjun
 * @Description:
 * @FilePath: \golib\fixedqueue\queue.go
 * hnxr
 */
package fixedqueue

import "encoding/json"

// 固定大小的队列
type FixQueue[G any] struct {
	array []*G
	Pos   uint //当前队列位置
	Idx   uint //累加器
	max   uint
}

/**
 * @description: 新建一个固定大小的队列
 * @return {*}
 */
func NewFixQueue[G any](size int) *FixQueue[G] {
	m := new(FixQueue[G])
	m.SetSize(size)
	return m
}

/**
 * @description: 初始化队列的最大值
 * @param {int} maxLines
 * @return {*}
 */
func (m *FixQueue[G]) SetSize(maxLines int) {
	if maxLines < 50 {
		maxLines = 50
	}
	if maxLines > 1000000 {
		maxLines = 1000000
	}
	m.array = make([]*G, maxLines)
	m.max = uint(maxLines)
	m.Idx = 0
	m.Pos = 0
}

/**
 * @description: 压入数据
 * @param {*EventLog} e
 * @return {*}
 */
func (m *FixQueue[G]) Push(e *G) {
	m.array[m.Pos] = e
	m.Idx++
	m.Pos = m.Idx % m.max
}

func (m *FixQueue[G]) Page(begin, limit int) []*G {
	end := begin + limit
	count := m.Size()

	if count == 0 {
		return nil
	}

	if begin > count {
		return nil
	}

	if limit > count {
		limit = count
	}

	if end > count {
		end = count
		limit = end - begin
	}
	rows := make([]*G, limit)

	idx := m.Idx
	pos := m.Pos
	if idx < m.max { //队列没有循环一次
		if uint(begin) > idx {
			return nil
		}
		if uint(end) > idx {
			end = int(idx)
		}
		//m.array[begin:end]
		ii := 0
		for i := end - 1; i >= begin; i-- {
			rows[ii] = m.array[i]
			ii++
		}
		return rows
	}
	//倒序
	for i := 0; i < limit; i++ {
		index := int(pos+m.max) + i
		index %= int(m.max)
		rows[limit-i-1] = m.array[index]
	}

	return rows
}

/**
 * @description: 获取队列数据大小
 * @param {*}
 * @return {*}
 */
func (m *FixQueue[G]) Size() int {
	if m.Idx >= m.max {
		return int(m.max)
	}
	return int(m.Idx)
}

// Write .
func (m *FixQueue[G]) Write(b []byte) (n int, err error) {
	e := new(G)
	err = json.Unmarshal(b, e)
	if err == nil {
		m.Push(e)
	}
	n = len(b)
	return
}
